/*
 * Copyright (C) 2001-2010 Jacek Sieka, arnetheduck on gmail point com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "stdafx.h"
#include "../client/DCPlusPlus.h"

#ifdef PPA_INCLUDE_STATS_FRAME
#include "Resource.h"

#include "../client/Socket.h"

#include "StatsFrame.h"
//[-]PPA [Doxygen 1.5.1] #include "WinUtil.h"
#ifdef PPA_INCLUDE_SHOW_UD_RATIO
int StatsFrame::columnIndexes[] =
{
	COLUMN_HUB,
	COLUMN_NICK,
	COLUMN_DOWNLOAD,
	COLUMN_UPLOAD
};
int StatsFrame::columnSizes[] = { 300, 100, 100, 100 };

static ResourceManager::Strings columnNames[] = { ResourceManager::FILE, ResourceManager::TYPE, ResourceManager::EXACT_SIZE,
                                                  ResourceManager::SIZE, ResourceManager::TTH_ROOT , ResourceManager::PATH, ResourceManager::DOWNLOADED,
                                                  ResourceManager::ADDED, ResourceManager::BITRATE
                                                }; //TODO // !PPA!

#endif

LRESULT StatsFrame::onCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	timerId = SetTimer(1, 1000);
	
	SetFont(WinUtil::font);
	
	bHandled = FALSE;
#ifdef PPA_INCLUDE_SHOW_UD_RATIO
	
	ctrlRatio.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS, WS_EX_CLIENTEDGE, IDC_UD_RATIO);
	ratioContainer.SubclassWindow(ctrlRatio);
	ctrlRatio.SetExtendedListViewStyle(LVS_EX_LABELTIP | LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | (BOOLSETTING(VIEW_GRIDCONTROLS) ? LVS_EX_GRIDLINES : 0));
	ctrlRatio.SetBkColor(WinUtil::bgColor);
	ctrlRatio.SetTextBkColor(WinUtil::bgColor);
	ctrlRatio.SetTextColor(WinUtil::textColor);
	
	for (uint8_t j = 0; j < COLUMN_LAST; j++)
	{
		ctrlRatio.InsertColumn(j, CTSTRING_I(columnNames[j]), LVCFMT_LEFT, columnSizes[j], j);
	}
#endif
	return 1;
}

LRESULT StatsFrame::onClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	if (!closed)
	{
		if (timerId != 0)
			KillTimer(timerId);
		// [+]IRainman
		DownloadManager::getInstance()->removeListener(this);
		UploadManager::getInstance()->removeListener(this);
		// [~]IRainman
			
		closed = true;
		WinUtil::setButtonPressed(IDC_NET_STATS, false);
		PostMessage(WM_CLOSE);
		return 0;
	}
	else
	{
		bHandled = FALSE;
		return 0;
	}
}

void StatsFrame::drawLine(CDC& dc, StatIter begin, StatIter end, CRect& rc, CRect& crc)
{
	int x = crc.right;
	
	StatIter i;
	for (i = begin; i != end; ++i)
	{
		if ((x - (int)i->scroll) < rc.right)
			break;
		x -= i->scroll;
	}
	if (i != end)
	{
		int y = (max == 0) ? 0 : (int)((i->speed * height) / max);
		dc.MoveTo(x, height - y);
		x -= i->scroll;
		++i;
		
		for (; i != end && x > twidth; ++i)
		{
			y = (max == 0) ? 0 : (int)((i->speed * height) / max);
			dc.LineTo(x, height - y);
			if (x < rc.left)
				break;
			x -= i->scroll;
		}
	}
}

LRESULT StatsFrame::onPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	if (GetUpdateRect(NULL))
	{
		CPaintDC dc(m_hWnd);
		CRect rc(dc.m_ps.rcPaint);
//[-]PPA        dcdebug("Update: %d, %d, %d, %d\n", rc.left, rc.top, rc.right, rc.bottom);

		dc.SelectBrush(backgr);
		dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), NULL, 0, 0, PATCOPY);
		
		CRect clientRC;
		GetClientRect(clientRC);
		
		dc.SetTextColor(WinUtil::textColor);
		dc.SetBkColor(WinUtil::bgColor);
		
		dc.SelectPen(foregr);
		dc.SelectFont(WinUtil::font);
		int lines = height / (WinUtil::fontHeight * LINE_HEIGHT);
		int lheight = height / (lines + 1);
		
		for (int i = 0; i < lines; ++i)
		{
			int ypos = lheight * (i + 1);
			if (ypos > WinUtil::fontHeight + 2)
			{
				dc.MoveTo(rc.left, ypos);
				dc.LineTo(rc.right, ypos);
			}
			
			if (rc.left <= twidth)
			{
			
				ypos -= WinUtil::fontHeight + 2;
				if (ypos < 0)
					ypos = 0;
				if (height == 0)
					height = 1;
				tstring txt = Util::formatBytesW(max * (height - ypos) / height) + _T("/") + CWSTRING(S);
				int tw = WinUtil::getTextWidth(txt, dc);
				if (tw + 2 > twidth)
					twidth = tw + 2;
				dc.TextOut(1, ypos, txt.c_str());
			}
		}
		
		if (rc.left < twidth)
		{
			tstring txt = Util::formatBytesW(max) + _T("/") + CWSTRING(S);
			int tw = WinUtil::getTextWidth(txt, dc);
			if (tw + 2 > twidth)
				twidth = tw + 2;
			dc.TextOut(1, 1, txt.c_str());
		}
		
		dc.SelectPen(m_UploadSocketPen);
		drawLine(dc, m_UpSockets, rc, clientRC);

		dc.SelectPen(m_DownloadSocketPen);
		drawLine(dc, m_DownSockets, rc, clientRC);
		// [+]IRainman
		dc.SelectPen(m_UploadsPen);
		drawLine(dc, m_Uploads, rc, clientRC);
		
		dc.SelectPen(m_DownloadsPen);
		drawLine(dc, m_Downloads, rc, clientRC);
		// [~]IRainman
	}
	return 0;
}

inline void StatsFrame::addTick(int64_t bdiff, uint64_t tdiff, StatList& lst, AvgList& avg, int scroll)
{
	int64_t bspeed = bdiff * (int64_t)1000 / tdiff;
	addSpeedTick(bspeed, lst, avg, scroll);
}

void StatsFrame::addSpeedTick(int64_t bspeed, StatList& lst, AvgList& avg, int scroll)
{
	avg.push_front(bspeed);
	
	bspeed = 0;
	
	for (AvgIter ai = avg.begin(); ai != avg.end(); ++ai)
	{
		bspeed += *ai;
	}
	
	bspeed /= avg.size();
	lst.push_front(Stat(scroll, bspeed));

	while ((int)lst.size() > ((width / PIX_PER_SEC) + 1))
	{
		lst.pop_back();
	}
	while (avg.size() > AVG_SIZE)
	{
		avg.pop_back();
	}
}

LRESULT StatsFrame::onTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	uint64_t tick = GET_TICK();
	uint64_t tdiff = tick - lastTick;
	if (tdiff == 0)
		return 0;
		
	uint64_t scrollms = (tdiff + scrollTick) * PIX_PER_SEC;
	uint64_t scroll = scrollms / 1000;
	
	if (scroll == 0)
		return 0;
		
	scrollTick = scrollms - (scroll * 1000);
	
	CRect rc;
	GetClientRect(rc);
	rc.left = twidth;
	ScrollWindow(-((int)scroll), 0, rc, rc);
	
	const int64_t d = Socket::getTotalDown();
	const int64_t ddiff = d - m_lastSocketsDown;
	const int64_t u = Socket::getTotalUp();
	const int64_t udiff = u - m_lastSocketsUp;

	const int64_t dt = DownloadManager::getInstance()->getRunningAverage();
	const int64_t ut = UploadManager::getInstance()->getRunningAverage();
	// [~]IRainman
	
	addTick(ddiff, tdiff, m_DownSockets, m_DownSocketsAvg, (int)scroll);
	addTick(udiff, tdiff, m_UpSockets, m_UpSocketsAvg, (int)scroll);
	// [+]IRainman
	addSpeedTick(dt, m_Downloads, m_DownloadsAvg, (int)scroll);
	addSpeedTick(ut, m_Uploads, m_UploadsAvg, (int)scroll);
	// [~]IRainman
	StatIter i;
	int64_t mspeed = 0;
	findMax(m_DownSockets, i, mspeed);
	findMax(m_UpSockets, i, mspeed);
	// [+]IRainman
	findMax(m_Downloads, i, mspeed);
	findMax(m_Uploads, i, mspeed);
	// [~]IRainman

	if (mspeed > max || ((max * 3 / 4) > mspeed))
	{
		max = mspeed;
		Invalidate();
	}
	
	lastTick = tick;
	m_lastSocketsUp = u;
	m_lastSocketsDown = d;

	return 0;
}

LRESULT StatsFrame::onSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	CRect rc;
	GetClientRect(rc);
	width = rc.Width();
	height = rc.Height() - 1;
	Invalidate();
	bHandled = FALSE;
	return 0;
}

void StatsFrame::UpdateLayout(BOOL /*bResizeBars*/ /* = TRUE */)
{

}
#endif
/**
 * @file
 * $Id: StatsFrame.cpp 463 2009-10-01 16:30:22Z BigMuscle $
 */
